use std::fs;
use std::fs::{File, OpenOptions, read_to_string};
use std::io::{Read, Write};
use std::path::Path;
use std::sync::OnceLock;

use anyhow::{anyhow, bail};
use log::error;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::client::hclient::HClient;
use crate::common::{CommError, CommResult};
use crate::util;

static CONFIG_INNER: OnceLock<ConfigInner> = OnceLock::new();
pub static HID: OnceLock<String> = OnceLock::new();

#[cfg(target_os = "windows")]
const HID_PATH: &str = "c:\\agentrs\\";
#[cfg(target_os = "linux")]
const HID_PATH: &str = "/etc/agentrs/";

pub struct ConfigInner {
    config_props: ConfigProps,
    path: String,
    hclient: HClient,
}

#[derive(Serialize, Deserialize, Default, PartialEq, Debug)]
pub struct ConfigProps {
    server: Server,
    log: Log,
}

#[derive(Serialize, Deserialize, Default, PartialEq, Debug)]
pub struct Server {
    host: String,
    port: String,
    context_path: String,
}

#[derive(Serialize, Deserialize, Default, PartialEq, Debug)]
pub struct Log {
    dir: String,
    level: String,
}

impl ConfigInner {
    pub fn get_server_host(&self) -> String {
        self.config_props.server.host.clone()
    }
    pub fn get_context_path(&self) -> String {
        self.config_props.server.context_path.clone()
    }
    pub fn get_server_port(&self) -> String {
        self.config_props.server.port.clone()
    }
    pub fn get_log_level(&self) -> String {
        self.config_props.log.level.clone()
    }
    pub fn get_log_dir(&self) -> String {
        self.config_props.log.dir.clone()
    }
}

// 初始化配置，加载hid
pub fn init(path: String) -> CommResult<()> {
    if let Ok(content) = read_to_string(&path) {
        let mut config_props: ConfigProps = serde_yaml::from_str(&content)?;
        let hclient = HClient::new(
            config_props.server.host.clone(),
            config_props.server.port.clone(),
            config_props.server.context_path.clone(),
        )?;
        let ci = ConfigInner {
            config_props,
            hclient,
            path,
        };
        CONFIG_INNER.get_or_init(|| ci);
    } else {
        bail!("配置文件取失败".to_string());
    }
    return Ok(());
}

/// 获取httpclient
pub fn get_hclient<'a>() -> CommResult<&'a HClient> {
    get_config_inner().map_or(Err(anyhow!("获取全局变量错误client")), |conf| {
        let hc = &conf.hclient;
        Ok(hc)
    })
}

fn get_config_inner<'a>() -> Option<&'a ConfigInner> {
    CONFIG_INNER.get()
}

pub fn get_server_host() -> String {
    get_config_inner().map_or(String::from("127.0.0.1"), |conf| conf.get_server_host())
}

pub fn get_server_port() -> String {
    get_config_inner().map_or(String::from("8024"), |conf| conf.get_server_port())
}

pub fn get_log_dir() -> String {
    let ss = get_config_inner();
    ss.map_or(String::from("logs"), |conf| conf.get_log_dir())
}

pub fn get_path() -> String {
    get_config_inner().map_or("".to_string(), |conf| conf.path.clone())
}

pub fn get_log_level() -> String {
    let ss = get_config_inner();
    ss.map_or(String::from("info"), |conf| conf.get_log_level())
}

pub fn get_hid_filepath() -> String {
    let dir = Path::new(HID_PATH);
    if !dir.exists() {
        if let Err(e) = fs::create_dir_all(dir) {
            error!("创建文件错误");
        }
    }
    dir.join("agenthid").to_str()
        .map_or("agenthid".to_string(), |s| s.to_string())
}

pub fn get_hid() -> String {
    match HID.get() {
        None => { String::from("000000") }
        Some(s) => {
            s.clone()
        }
    }
}

pub fn exist_hid_file() -> bool {
    let path = get_hid_filepath();
    let exits = Path::new(&path).exists();
    exits
}

//从文件中加载唯一主机id
pub fn load_hid() -> CommResult<()> {
    if !exist_hid_file() {
        return Ok(());
    }
    let path = get_hid_filepath();
    // 打开要读取的文件
    match File::open(path.as_str()) {
        Ok(mut f) => {
            // 读取输入文件的内容
            let mut content = String::new();
            if let Err(e) = f.read_to_string(&mut content) {
                error!("read hid err->{}",e);
                bail!(e);
            }
            if let Err(e) = HID.set(content.clone()) {
                error!("hid set err-> {}",e)
            }
            if content.is_empty() {
                bail!("hid文件为空");
            }
            Ok(())
        }
        Err(e) => {
            error!("打开文件失败>{}",e);
            bail!(e)
        }
    }
}

// pub fn rand_hid() -> String {
//     let uuid = Uuid::new_v4();
//     let s = util::md5(uuid.to_string());
//     s
// }

pub fn save_hid(path: String, s: String) -> CommResult<()> {
    let mut options = OpenOptions::new();
    // options.access_mode(0o644);
    options.read(true).write(true).append(true).create(true);
    let file = options.open(path.as_str());
    match file {
        Ok(mut f) => {
            if let Err(e) = f.write(&s.as_bytes()) {
                error!("写入文件hid err->{}",e);
                bail!(e)
            }
            if let Err(e) = f.flush() {
                error!("写入文件hid err->{}",e);
            }
            Ok(())
        }
        Err(e) => {
            error!("创建hid文件失败>{}",e);
            bail!(e)
        }
    }
}
